package SnmpAll;

import AppletInterface.AppletStart;
import AppletInterface.AppletStartEvent;
import AppletInterface.AppletStartListener;
import BaseClasses.DataInterface;
import SnmpClients.SnmpClientV2c;
import SnmpClients.SnmpClienteV3;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.smi.OID;

/**
 * Thread encarregue de fazer os pedidos ao agente através dos clientes snmp com um intervalo de tempo igual ao tempo de polling e guardar os resultados, lançando um evento de seguida para notificar a interface.
 * 
 */
public class SnmpFetcher extends Thread {

    private volatile SnmpClienteV3 scv3;
    private volatile SnmpClientV2c scv2c;
    private volatile SnmpData sData;
    private volatile int numInterfaces;
    private volatile float pollingTime;
    private AppletStartListener apl;
    private AppletStart as;

    /**
     * 
     * @param scv3 Cliente SNMP versão 3 (nullo caso seja usada a versão 2)
     * @param scv2c Cliente SNMP versão 2c (nullo caso seja usada a terceira versão)
     * @param sData Lista com todos os interfaces e respectivas informações
     * @param pollingTime Tempo de polling ao agente
     * @param apl Listener da AppletStart (utilizado para notificar a interface)
     * @param as instância do AppletStart, (necessário para que a applet se actualize)
     */
    public SnmpFetcher(SnmpClienteV3 scv3, SnmpClientV2c scv2c, SnmpData sData, float pollingTime, AppletStartListener apl, AppletStart as) {
        this.scv3 = scv3;
        this.scv2c = scv2c;
        this.sData = sData;
        this.pollingTime = pollingTime;
        this.numInterfaces = 0;
        this.apl = apl;
        this.as = as;
    }

    //<editor-fold defaultstate="collapsed" desc="Gets">
    /**
     * 
     * @return
     */
    public SnmpData getSData() {
        return this.sData;
    }

    /**
     * 
     * @return
     */
    public int getNumInterfaces() {
        return this.numInterfaces;
    }

    /**
     * 
     * @return
     */
    public float getPollingTime() {
        return this.pollingTime;
    }
    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc="Sets">
    /**
     * 
     * @param sData
     */
    public void setSData(SnmpData sData) {
        this.sData = sData;
    }
    //</editor-fold>

    /**
     * Função principal da Thread, responsável por efectuar todas as tarefas descritas para esta classe
     */
    @Override
    public void run() {

        if (this.scv3 != null) {
            //<editor-fold defaultstate="collapsed" desc="Cliente SnmpV3">
            while (true) {
                try {
                    this.numInterfaces = Integer.parseInt(scv3.getAsString(new OID("1.3.6.1.2.1.2.1.0")));

                    //adicionar novas interfaces -> se houver
                    for (int i = 1; i <= this.numInterfaces; i++) {
                        String s;

                        boolean found = false;
                        for (DataInterface df : this.sData.getArrayListInterfacesClone()) {
                            if (df.getNome().equals(this.scv3.getAsString(new OID("1.3.6.1.2.1.2.2.1.2." + i)))) {
                                found = true;
                            }
                        }

                        if (!found) {
                            DataInterface e = new DataInterface();

                            //Lista com todos os oid desejados
                            OID[] oid = new OID[]{new OID("1.3.6.1.2.1.2.2.1.2." + i),
                                new OID("1.3.6.1.2.1.2.2.1.8." + i),
                                new OID("1.3.6.1.2.1.2.2.1.5." + i),
                                new OID("1.3.6.1.2.1.2.2.1.16." + i),
                                new OID("1.3.6.1.2.1.2.2.1.10." + i),
                                new OID("1.3.6.1.2.1.1.3.0")};

                            //Pedir os valores de todos os objectos desejados
                            ResponseEvent re = this.scv3.getListAsString(oid);


                            //Nome da Interface
                            s = re.getResponse().get(0).getVariable().toString();
                            e.setNome(s);

                            //OID da Interface
                            e.setOidInterface(i);

                            //Estado Interfaces
                            s = re.getResponse().get(1).getVariable().toString();

                            if (Integer.parseInt(s) == 1) {
                                e.setEstado("Up");
                            } else {
                                e.setEstado("Down");
                            }

                            //System.out.println("Estado: " + s);

                            // Banda Larga Nominal
                            s = re.getResponse().get(2).getVariable().toString();
                            e.setLarguraBandaNominal(Long.parseLong(s) / (100000));
                            //System.out.println("Banda Larga Nominal: " + (Long.parseLong(s) / (100000)) + " Mbps");

                            // Numero de octectos contados até agora (Output)
                            s = re.getResponse().get(3).getVariable().toString();
                            long outPut = Long.parseLong(s);
                            //System.out.println("Numero de octectos (Output)" + s);

                            // Numero de octectos contados até agora (Input)
                            s = re.getResponse().get(4).getVariable().toString();
                            long inPut = Long.parseLong(s);
                            //System.out.println("Numero de octectos (Input)" + s);

                            //tempo em que os valores dos objectos foram retirados da mib
                            e.adicionarValor(re.getResponse().get(5).getVariable().toLong(),outPut, inPut);

                            this.sData.getArrayListInterfaces().add(e);
                        }
                    }

                    //Refrescar os valor do interfaces já existentes
                    for (DataInterface df : this.sData.getArrayListInterfaces()) {
                        String s;

                        //Lista com todos os oid desejados
                        OID[] oid = new OID[]{new OID("1.3.6.1.2.1.2.2.1.8." + df.getOidInterface()),
                            new OID("1.3.6.1.2.1.2.2.1.16." + df.getOidInterface()),
                            new OID("1.3.6.1.2.1.2.2.1.10." + df.getOidInterface()),
                            new OID("1.3.6.1.2.1.1.3.0")};

                        //Pedir os valores de todos os objectos desejados
                        ResponseEvent re = this.scv3.getListAsString(oid);

                        //Estado Interfaces
                        s = re.getResponse().get(0).getVariable().toString();

                        if (Integer.parseInt(s) == 1) {
                            df.setEstado("Up");
                        } else {
                            df.setEstado("Down");
                        }

                        // Numero de octectos contados até agora (Output)
                        s = re.getResponse().get(1).getVariable().toString();
                        long outPut = Long.parseLong(s);
                        //System.out.println("Numero de octectos (Output)" + s);

                        // Numero de octectos contados até agora (Input)
                        s = re.getResponse().get(2).getVariable().toString();
                        long inPut = Long.parseLong(s);
                        //System.out.println("Numero de octectos (Input)" + s);

                        //tempo em que os valores dos objectos foram retirados da mib
                        df.adicionarValor(re.getResponse().get(3).getVariable().toLong(),outPut, inPut);
                    }
                    try {
                        //Notificar a interface que existem novos valores
                        apl.actualiza(new AppletStartEvent(as));
                        //Stand-by desta Thread
                        Thread.sleep((long) pollingTime * 1000);
                        //</editor-fold>
                    } catch (InterruptedException ex) {
                        Logger.getLogger(SnmpFetcher.class.getName()).log(Level.SEVERE, null, ex);
                    }
                } catch (IOException ex) {
                    Logger.getLogger(SnmpFetcher.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        } else if (this.scv2c != null) {
            //<editor-fold defaultstate="collapsed" desc="Cliente SnmpV2c">
            while (true) {
                try {
                    this.numInterfaces = Integer.parseInt(scv2c.getAsString(new OID("1.3.6.1.2.1.2.1.0")));

                    //adicionar novas interfaces -> se houver
                    for (int i = 1; i <= this.numInterfaces; i++) {
                        String s;

                        boolean found = false;
                        for (DataInterface df : this.sData.getArrayListInterfacesClone()) {
                            if (df.getNome().equals(this.scv2c.getAsString(new OID("1.3.6.1.2.1.2.2.1.2." + i)))) {
                                found = true;
                            }
                        }

                        if (!found) {
                            DataInterface e = new DataInterface();

                            //Lista com todos os oid desejados
                            OID[] oid = new OID[]{new OID("1.3.6.1.2.1.2.2.1.2." + i),
                                new OID("1.3.6.1.2.1.2.2.1.8." + i),
                                new OID("1.3.6.1.2.1.2.2.1.5." + i),
                                new OID("1.3.6.1.2.1.2.2.1.16." + i),
                                new OID("1.3.6.1.2.1.2.2.1.10." + i),
                                new OID("1.3.6.1.2.1.1.3.0")};

                            //Pedir os valores de todos os objectos desejados
                            ResponseEvent re = this.scv2c.getListAsString(oid);


                            //Nome da Interface
                            s = re.getResponse().get(0).getVariable().toString();
                            e.setNome(s);

                            //OID da Interface
                            e.setOidInterface(i);

                            //Estado Interfaces
                            s = re.getResponse().get(1).getVariable().toString();

                            if (Integer.parseInt(s) == 1) {
                                e.setEstado("Up");
                            } else {
                                e.setEstado("Down");
                            }

                            //System.out.println("Estado: " + s);

                            // Banda Larga Nominal
                            s = re.getResponse().get(2).getVariable().toString();
                            e.setLarguraBandaNominal(Long.parseLong(s) / (100000));
                            //System.out.println("Banda Larga Nominal: " + (Long.parseLong(s) / (100000)) + " Mbps");

                            // Numero de octectos contados até agora (Output)
                            s = re.getResponse().get(3).getVariable().toString();
                            long outPut = Long.parseLong(s);
                            //System.out.println("Numero de octectos (Output)" + s);

                            // Numero de octectos contados até agora (Input)
                            s = re.getResponse().get(4).getVariable().toString();
                            long inPut = Long.parseLong(s);
                            //System.out.println("Numero de octectos (Input)" + s);

                            //tempo em que os valores dos objectos foram retirados da mib
                            e.adicionarValor(re.getResponse().get(5).getVariable().toLong(),outPut, inPut);

                            this.sData.getArrayListInterfaces().add(e);
                        }
                    }

                    //Refrescar os valor do interfaces já existentes
                    for (DataInterface df : this.sData.getArrayListInterfaces()) {
                        String s;

                        //Lista com todos os oid desejados
                        OID[] oid = new OID[]{new OID("1.3.6.1.2.1.2.2.1.8." + df.getOidInterface()),
                            new OID("1.3.6.1.2.1.2.2.1.16." + df.getOidInterface()),
                            new OID("1.3.6.1.2.1.2.2.1.10." + df.getOidInterface()),
                            new OID("1.3.6.1.2.1.1.3.0")};

                        //Pedir os valores de todos os objectos desejados
                        ResponseEvent re = this.scv3.getListAsString(oid);

                        //Estado Interfaces
                        s = re.getResponse().get(0).getVariable().toString();

                        if (Integer.parseInt(s) == 1) {
                            df.setEstado("Up");
                        } else {
                            df.setEstado("Down");
                        }

                        // Numero de octectos contados até agora (Output)
                        s = re.getResponse().get(1).getVariable().toString();
                        long outPut = Long.parseLong(s);
                        //System.out.println("Numero de octectos (Output)" + s);

                        // Numero de octectos contados até agora (Input)
                        s = re.getResponse().get(2).getVariable().toString();
                        long inPut = Long.parseLong(s);
                        //System.out.println("Numero de octectos (Input)" + s);

                        //tempo em que os valores dos objectos foram retirados da mib
                        df.adicionarValor(re.getResponse().get(3).getVariable().toLong(),outPut, inPut);
                    }
                    try {
                        //Notificar a interface que existem novos valores
                        apl.actualiza(new AppletStartEvent(as));
                        //Stand-by desta Thread
                        Thread.sleep((long) pollingTime * 1000);
                        //</editor-fold>
                    } catch (InterruptedException ex) {
                        Logger.getLogger(SnmpFetcher.class.getName()).log(Level.SEVERE, null, ex);
                    }
                } catch (IOException ex) {
                    Logger.getLogger(SnmpFetcher.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }
}
